﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.ComponentModel;

namespace Spore.Utils
{
     public abstract class ChannelBase<T>:INetChannel
    {
        protected Socket socket;
        protected SocketAsyncEventArgs readAsy;
        protected SocketAsyncEventArgs writeAsy;
        protected bool stop;
        private Buffer<T> bufferReader;
        public Buffer<T> BufferReader
        {
            get { return bufferReader; }
        }
        protected Buffer<T> bufferWriter;
        protected object obj_lock=new object();
        protected bool writing;
        protected int Connectedflag;
        public int ChannelID
        {
            get;
            set;
        }
        
        /// <summary>
        /// 数据通道内部错误事件
        /// </summary>
        public event Action<bool,SocketError,CancelEventArgs> ChannelErrorEventHandle;

        public event Action<ChannelBase<T>> ReadDataCompeletedEventHandle;

        public event Action<ChannelBase<T>> ChannelClosedEventHandle;

        public ChannelBase(Socket socket)
        {
            this.socket = socket;
            this.bufferReader = new Buffer<T>(100);
            this.bufferWriter = new Buffer<T>(100);
            readAsy = new SocketAsyncEventArgs();
            writeAsy = new SocketAsyncEventArgs();
            readAsy.Completed += (sender, e) => OnReadComplete();
            writeAsy.Completed += (sender, e) => OnWriteComplete();
        }

        public ChannelBase(Socket socket, Buffer<T> bufferReader, Buffer<T> bufferWriter)
        {

            this.socket = socket;
            this.bufferReader = new Buffer<T>(100);
            this.bufferWriter = new Buffer<T>(100);
            readAsy = new SocketAsyncEventArgs();
            writeAsy = new SocketAsyncEventArgs();
            readAsy.Completed += (sender, e) => OnReadComplete();
            writeAsy.Completed += (sender, e) => OnWriteComplete();
            this.bufferReader = bufferReader;
            this.bufferWriter = bufferWriter;
        }

        protected void OnWriteComplete()
        {
            if (this.writeAsy.SocketError != SocketError.Success)
            {
                CancelEventArgs e = new CancelEventArgs(false);
                this.OnChannelError(false, writeAsy.SocketError, e);
                if (!e.Cancel)
                    return;
            }
            else
            {
                if(!this.stop)
                this.OnWriteData();
            }
        }

         public void WriteData(params T[] willWriteData)
         {
          
             lock (obj_lock)
             {
                 this.bufferWriter.AddRangeElement(willWriteData);
                 if (!this.writing)
                 {
                     this.OnWriteData();
                 }
             }
         }

        protected void OnReadComplete()
        {
            if (this.writeAsy.SocketError != SocketError.Success)
            {
                CancelEventArgs e = new CancelEventArgs(false);
                this.OnChannelError(false, writeAsy.SocketError, e);
                if (!e.Cancel)
                    return;
            }
            if (!this.stop)
            {
                if (this.socket.Available == 0)
                {
                    if (this.Connectedflag++ > 4)
                    {
                        this.Close();
                        Console.WriteLine("远程连接已断开");
                    }
                    else
                        this.OnReadData();
                }
                else
                {
                    this.Connectedflag = 0;
                    this.OnReadData();
                }
            }
        }

        protected virtual void OnChannelError(bool isReadError,SocketError error,CancelEventArgs e)
        {
            Loger.Error(string.Format("数据通道错误：是否为读错误{0},错误代码：{1}", isReadError, error));
#if DEBUG
            System.Diagnostics.Debug.Assert(false, "数据通道错误:" + error.ToString());
#endif 
            if (this.ChannelErrorEventHandle != null)
            {
                this.ChannelErrorEventHandle(isReadError, error, e);
            }
            if (!e.Cancel)
            {
                this.Close();
            }
        }

        protected abstract void OnReadData();

        protected abstract void OnWriteData();

        protected virtual void OnReadElement()
        {
            if (this.ReadDataCompeletedEventHandle != null)
                this.ReadDataCompeletedEventHandle(this);
        }

        #region INetChannel 成员

        public  void Open()
        {
            if (this.Status != ChannelStatus.UnOpen)
            {
                Loger.Error("数据通道已经打开");
                return;
            }
            try
            {
                this.Status = ChannelStatus.Opening;
                this.OnOpen();
                this.Status = ChannelStatus.Opened;
            }
            catch (Exception ex)
            {
                Loger.Error("开启数据通道发生错误："+ex.Message);
            }
            
        }

        protected virtual void OnOpen()
        {
 
        }

        public  void Close()
        {
            if (this.Status!= ChannelStatus.Opened)
            {
                Loger.Error("数据通道不在关闭状态");
                return;
            }
            this.Status = ChannelStatus.Closing;
            this.OnClose();
            this.bufferReader.GetAndRemoveAllElement();
            this.bufferWriter.GetAndRemoveAllElement();
            try
            {
                this.socket.Shutdown(SocketShutdown.Both);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            this.socket.Close();
            this.Status = ChannelStatus.Closed;
            if (this.ChannelClosedEventHandle != null)
                this.ChannelClosedEventHandle(this);
        }

        protected virtual void OnClose()
        {
 
        }


        public ChannelStatus Status
        {
            get;
            private set;
        }
        #endregion
    }
}
